package jeconbond.economic.market.agent.service;

import jeconbond.economic.agent.service.IPostActServiceAgent;
import jeconbond.economic.agent.IEconomicProducer;
import jeconbond.economic.resources.IResourceType;
import jeconbond.economic.systems.market.IMarketResourceRedestributionSystem;
import jeconbond.economic.systems.market.IMoneyAccount;
import jeconbond.economic.systems.market.ISellProposition;
import jeconbond.economic.systems.market.ISellsListener;

import java.util.*;
import java.util.Map.Entry;

public class SpySellsAgent implements IPostActServiceAgent, ISellsListener {
	IMarketResourceRedestributionSystem mrrs;
	int[] stepsCounter_ptr;
	
	private int prevCounterVal = 0;
	
	private Map<IResourceType, double[]> type2cost = 
		new HashMap<IResourceType, double[]>();
	private Map<IResourceType, double[]> type2value = 
		new HashMap<IResourceType, double[]>();
	private Map<IResourceType, List<Double>> type2priceTrack = 
		new HashMap<IResourceType, List<Double>>();
	private Map<IResourceType, List<Double>> type2valueTrack = 
		new HashMap<IResourceType, List<Double>>();
	private Set<IMoneyAccount> ignoreBuyersMoneyAcc =
			new HashSet<IMoneyAccount>();

	public SpySellsAgent(
			IMarketResourceRedestributionSystem mrrs,
			int[] stepsCounter_ptr, 
			IResourceType[] resources
	) {
		this.mrrs = mrrs;
		this.stepsCounter_ptr = stepsCounter_ptr;
		mrrs.addSellsListener(this);
		for (IResourceType type : resources) {
			type2cost.put(type, new double[1]);
			type2value.put(type, new double[1]);
			type2priceTrack.put(type, new ArrayList<Double>());
			type2valueTrack.put(type, new ArrayList<Double>());
		}
	}
	
	public Map<IResourceType, List<Double>> getType2priceTrack() {
		flushResults();
		return type2priceTrack;
	}

	public Map<IResourceType, List<Double>> getType2valueTrack() {
		flushResults();
		return type2valueTrack;
	}

	@Override
	public void processPostProduceStage() {
		flushResults();
		prevCounterVal = stepsCounter_ptr[0];
	}

	@Override
	public void processPreProduceStage() {}
	
	private static void clearMap(Map<IResourceType, double[]> map) {
		for (Entry<IResourceType, double[]> entry : map.entrySet()) {
			entry.getValue()[0] = 0.0;
		}
	}

	@Override
	public void processProduceStage() {}

	@Override
	public void onSellPerformed(ISellProposition proposition, double value, IMoneyAccount buyerAccount) {
		if (ignoreBuyersMoneyAcc.contains(buyerAccount)) {
			return;
		}
		double cost = proposition.getPrice() * value;
		double[] resCost_ptr = type2cost.get(proposition.getType());
		resCost_ptr[0] += cost;
		double[] sellsVal_ptr = type2value.get(proposition.getType());
		sellsVal_ptr[0] += value;
	}

	public void addIgnoreBuyer(IEconomicProducer producer) {
		ignoreBuyersMoneyAcc.add(producer.getMerchant().getMoneyAccount());	
	}

	private void flushResults() {
		if (stepsCounter_ptr[0] > prevCounterVal) {
			writeTrackNotes();
			clearMap(type2cost);
			clearMap(type2value);
		}
	}

	private void writeTrackNotes() {
		for (IResourceType type : type2cost.keySet()) {
			double cost = type2cost.get(type)[0];
			double value = type2value.get(type)[0];
			double averPrice = cost / value;
			type2priceTrack.get(type).add(averPrice);
			type2valueTrack.get(type).add(value);
		}
	}
}
